home *** CD-ROM | disk | FTP | other *** search
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
- PREREQUISITES FOR THIS MATERIAL
-
- In order to understand this chapter, you should have a
- good grasp of the entirety of Part I and a clear
- understanding of chapter 11.
-
- For certain types of programs, pointers and dynamic
- allocation can be a tremendous advantage, but most programs
- do not need such a high degree of data structure. For that
- reason, it would probably be to your advantage to lightly
- skim over these topics and come back to them later when you
- have a substantial base of Modula-2 programming experience.
- It would be good to at least skim over this material rather
- than completely neglecting it, so you will have an idea of
- how pointers and dynamic allocation work and that they are
- available for your use when needed.
-
- A complete understanding of this material will require
- deep concentration as it is very complex and not at all
- intuitive. Nevertheless, if you pay close attention, you
- will have a good grasp of pointers and dynamic allocation in
- a short time.
-
- WHAT ARE POINTERS, AND WHAT GOOD ARE THEY?
-
- If you examine POINTERS.MOD, you will see a very trivial
- example of pointers and how they are used. In the VAR
- declaration, you will see that the two variables have the
- two reserved words POINTER TO in front of their respective
- types. These are not actually variables, instead, they
- point to dynamically allocated variables that have not been
- defined yet, and they are called pointers. We will see,
- when we get to chapter 14, that a pointer can be used to
- point to any variable, even a statically defined one, but
- that will have to wait awhile.
-
- The pointer "MyName" is a pointer to a 20 character
- string and is therefore not a variable into which a value
- can be stored. This is a very special TYPE, and it cannot
- be assigned a character string, only a pointer value or
- address. The pointer actually points to an address
- somewhere within the computer memory, and can access the
- data stored at that address.
-
- Your computer has some amount of memory installed in it.
- If it is an IBM-PC or compatible, it can have up to 640K of
- RAM which is addressable by various programs. The operating
- system requires about 60K of the total, and your program can
- use up to 64K assuming that your compiler uses a small
- memory model. Adding those two numbers together results in
- about 124K. Any memory you have installed in excess of that
-
-
- Page 72
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
- is available for the stack and the heap. The stack is a
- standard DOS defined and controlled area that can grow and
- shrink as needed. Many books are available to define the
- stack if you are interested in more information on it.
-
- The heap is a Modula-2 entity that utilizes otherwise
- unused memory to store data. It begins immediately
- following the program and grows as necessary upward toward
- the stack which is growing downward. As long as they never
- meet, there is no problem. If they meet, a run-time error
- is generated. The heap is therefore outside of the actual
- program space.
-
- If you did not understand the last two paragraphs, don't
- worry. Simply remember that dynamically allocated variables
- are stored on the heap and do not count in the 64K
- limitation placed upon you by some compilers.
-
- Back to our example program, POINTERS.MOD. When we
- actually begin executing the program, we still have not
- defined the variables we wish to use to store data in. The
- first executable statement in line 15 generates a variable
- for us with no name and stores it on the heap. Since it has
- no name, we cannot do anything with it, except for the fact
- that we do have a pointer "MyAge" that is pointing to it.
- By using the pointer, we can store any INTEGER in it,
- because that is its type, and later go back and retrieve it.
-
- WHAT IS DYNAMIC ALLOCATION?
-
- The variable we have just described is a dynamically
- allocated variable because it was not defined in a VAR
- declaration, but with an ALLOCATE procedure. The ALLOCATE
- procedure creates a variable of the type defined by the
- pointer, puts it on the heap, and finally assigns the
- address of the variable to the pointer itself. Thus "MyAge"
- contains the address of the variable generated. The
- variable itself is referenced by using the pointer to it
- followed by a ^, and is read, "the variable to which the
- pointer points".
-
- The ALLOCATE procedure requires 2 arguments, the first
- of which is a pointer which will be used to point to the
- desired new block of dynamically allocated menory, and the
- second which gives the size of the block in bytes. The
- supplied function TSIZE will return the size of the block of
- data required by the TYPE supplied to it as an argument. Be
- sure to use the TYPE of the data and not the TYPE of the
- pointer to the data for the argument. Another procedure is
- available named SIZE which returns the size of any variable
- in bytes.
-
-
- Page 73
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
-
- The next statement assigns a place on the heap to an
- ARRAY type variable and puts its address in "MyName".
- Following the ALLOCATE statements we have two assignment
- statements in which the two variables pointed at are
- assigned values compatible with their respective types, and
- they are both written out to the video display. Notice that
- both of these operations use the ^ which is the dereference
- operator. By adding the dereference operator to the pointer
- name, you can use the entire name just like any other
- variable name.
-
- The last two statements are illustrations of the way the
- dynamically allocated variables are removed from use. When
- they are no longer needed, they are disposed of with the
- DEALLOCATE procedure, and the space on the heap is freed up
- for use by other dynamically allocated variables.
-
- In such a simple program, pointers cannot be
- appreciated, but it is necessary for a simple illustration.
- In a large, very active program, it is possible to define
- many variables, dispose of some of them, define more, and
- dispose of more, etc. Each time some variables are
- deallocated, their space is then made available for
- additional variables defined with the ALLOCATE procedure.
-
- The heap can be made up of any assortment of variables,
- they do not have to all be the same. One thing must be
- remembered. Anytime a variable is defined, it will have a
- pointer pointing to it. The pointer is the only means by
- which the variable can be accessed. If the pointer to the
- variable is lost or changed, the data itself is lost for all
- practical purposes.
-
- WHAT ABOUT THE "NEW" AND "DISPOSE" PROCEDURES?
-
- The NEW and DISPOSE procedures are a carryover from
- Pascal and are available on some Modula-2 compilers. When
- they are available, they are simply translated internally
- into calls to ALLOCATE and DEALLOCATE which must be imported
- in order to use NEW and DISPOSE. Since they are being
- removed from the language definition, their use should be
- discouraged in favor of the more universal ALLOCATE and
- DEALLOCATE procedures.
-
- DYNAMICALLY STORING RECORDS;
-
- The next example program, DYNREC.MOD, is a repeat of one
- we studied in an earlier chapter. For your own edification,
- review the example program BIGREC.MOD before going ahead in
- this chapter.
-
-
- Page 74
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
-
- Assuming that you are back in DYNREC.MOD, you will
- notice that this program looks very similar to the earlier
- one, and in fact they do exactly the same thing. The only
- difference in the TYPE declaration is the addition of a
- pointer "PersonID", and in the VAR declaration, the first
- four variables are defined as pointers here, and were
- defined as record variables in the last program.
-
- WE JUST BROKE THE GREAT RULE OF MODULA-2
-
- Notice in the TYPE declaration that we used the
- identifier "Person" before we defined it, which is illegal
- in Modula-2. Foreseeing the need to define a pointer prior
- to the record, the designer of Modula-2 allows us to break
- the rule in this one place. The pointer could have been
- defined after the record in this case, but it was more
- convenient to put it before, and in the next example
- program, it will be required to put it before the record.
- We will get there soon.
-
- Examining the VAR declaration, we see that "Friend" is
- really 50 pointers, so we have now defined 53 different
- pointers to records, but no variables other than "Temp" and
- "Index". We dynamically allocate a record with "Self"
- pointing to it, and use the pointer to fill the new record.
- Compare the statements that fill the record with the
- corresponding statements in "BIGREC" and you will see that
- they are identical except for the addition of the ^ to each
- use of the pointer to designate the data pointed to.
-
- THIS IS A TRICK, BE CAREFUL
-
- Now go down to the place where "Mother" is assigned a
- record and is then pointing to the record. It seems an easy
- thing to do then to simply assign all of the values of
- "Self" to all the values of "Mother" as shown in the next
- statement, but it doesn't work. All the statement does, is
- make the pointer "Mother" point to the same place where
- "Self" is pointing. The data space that was allocated to
- the pointer "Mother" is now somewhere on the heap, but since
- we have lost the original pointer to it, we cannot find it,
- use it, or deallocate it. This is an example of losing data
- on the heap. The proper way is given in the next two
- statements where all fields of "Father" are defined by all
- fields of "Mother" which is pointing at the original "Self"
- record. Note that since "Mother" and "Self" are both
- pointing at the same record, changing the data with either
- pointer results in the data appearing to be changed in both
- because there is, in fact, only one data field.
-
-
-
- Page 75
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
- A NOTE FOR PASCAL PROGRAMMERS
-
- In order to WRITE from or READ into a dynamically
- assigned record it is necessary to use a temporary record
- since dynamically assigned records are not allowed to be
- used in I/O statements in Pascal. This is not true in
- Modula-2, and you can write directly out of a dynamically
- allocated record in Modula-2. This is illustrated in the
- section of the program that writes some data to the monitor.
-
- Finally, the dynamically allocated variables are
- deallocated prior to ending the program. For a simple
- program such as this, it is not necessary to deallocate them
- because all dynamic variables are deallocated automatically
- when the program is terminated, but the DEALLOCATE steps are
- included for illustration. Notice that if the
- "DEALLOCATE(Mother)" statement was included in the program,
- the data could not be found due to the lost pointer, and the
- program would be unpredictable, probably leading to a system
- crash.
-
- SO WHAT GOOD IS THIS ANYWAY?
-
- Remember when you were initially studying BIGREC? I
- suggested that you see how big you could make the constant
- "NumberOfFriends" before you ran out of memory. At that
- time you probably found that it could be made slightly
- greater than 1000 before you got the memory overflow message
- at compilation. If your compiler uses a large memory model,
- you may have been able to go much larger. Try the same
- thing with DYNREC to see how many records it can handle,
- remembering that the records are created dynamically, so you
- will have to run the program to actually run out of memory.
- The final result will depend on how much memory you have
- installed, and how many memory resident programs you are
- using such as "Sidekick". If you have a full memory of
- 640K, I would suggest you start somewhere around 8000
- records of "Friend".
-
- Now you should have a good idea of why Dynamic
- Allocation can be used to greatly increase the usefulness of
- your programs. There is, however, one more important topic
- we must cover on dynamic allocation. That is the linked
- list.
-
- WHAT IS A LINKED LIST?
-
- Understanding and using a linked list is by far the most
- baffling topic you will confront in Modula-2. Many people
- simply throw up their hands and never try to use a linked
- list. I will try to help you understand it by use of an
-
-
- Page 76
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
- example and lots of explanation. Examine the program
- LINKLIST.MOD for an example of a linked list. I tried to
- keep it short so you could see the entire operation and yet
- do something meaningful.
-
- To begin with, notice that there are two TYPEs defined,
- a pointer to the record and the record itself. The record,
- however, has one thing about it that is new to us, the last
- entry, "Next" is a pointer to this very record. This record
- then, has the ability to point to itself, which would be
- trivial and meaningless, or to another record of the same
- type which would be extremely useful in some cases. In
- fact, this is the way a linked list is used. I must point
- out, that the pointer to another record, in this case called
- "Next", does not have to be last in the list, it can be
- anywhere it is convenient for you.
-
- A couple of pages ago, we discussed the fact that we had
- to break the great rule of Modula-2 and use an identifier
- before it was defined. This is the reason the exception to
- the rule was allowed. Since the pointer points to the
- record, and the record contains a reference to the pointer,
- one has to be defined after being used, and by rules of
- Modula-2, the pointer can be defined first. That is a
- mouthful but if you just use the syntax shown in the
- example, you will not get into trouble with it.
-
- STILL NO VARIABLES?
-
- It may seem strange, but we still will have no variables
- defined, except for our old friend "Index". In fact for
- this example, we will only define 3 pointers. In the last
- example we defined 54 pointers, and had lots of storage
- room. Before we are finished, we will have at least a dozen
- pointers but they will be stored in our records, so they too
- will be dynamically allocated.
-
- Lets look at the program itself now. First, we create a
- dynamically allocated record and define it by the pointer
- "PlaceInList". It is composed of the three data fields, and
- another pointer. We define "StartOfList" to point to the
- first record created, and we will leave it unchanged
- throughout the program. The pointer "StartOfList" will
- always point to the first record in the linked list which we
- are building up.
-
- We define the three variables in the record to be any
- name we desire for illustrative purposes, and set the
- pointer in the record to NIL. NIL is a reserved word that
- doesn't put an address in the pointer but defines it as
- empty. A pointer that is currently NIL cannot be used to
-
-
- Page 77
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
- write a value to the display as it has no value, but it can
- be tested in a logical statement to see if it is NIL. It is
- therefore a dummy assignment. With all of that, the first
- record is completely defined.
-
- DEFINING THE SECOND RECORD
-
- When you were young you may have played a searching
- game in which you were given a clue telling you where the
- next clue was at. The next clue had a clue to the location
- of the third clue. You kept going from clue to clue until
- you found the prize. You simply exercised a linked list.
- We will now build up the same kind of a list in which each
- record will tell us where the next record is at.
-
- We will now define the second record. Our goal will be
- to store a pointer to the second record in the pointer field
- of the first record. In order to keep track of the last
- record, the one in which we need to update the pointer, we
- will keep a pointer to it in "TempPlace". Now we can create
- another new record and use "PlaceInList" to point to it.
- Since "TempPlace" is still pointing at the first record, we
- can use it to store the value of the pointer to the new
- record in the old record. The 3 data fields of the new
- record are assigned nonsense data for our illustration, and
- the pointer field of the new record is assigned NIL.
-
- Lets review our progress to this point. We now have the
- first record with a name, composed of 3 parts, and a pointer
- to the second record. We also have a second record storing a
- different name and a pointer assigned NIL. We also have
- three pointers, one pointing to the first record, one
- pointing to the last record, and one we used just to get
- here since it is only a temporary pointer. If you
- understand what is happening so far, lets go on to add some
- additional records to the list. If you are confused, go
- back over this material again.
-
- TEN MORE RECORDS
-
- The next section of code is contained within a FOR loop
- so the statements are simply repeated ten times. If you
- observe carefully, you will notice that the statements are
- identical to the second group of statements in the program
- (except of course for the name assigned). They operate in
- exactly the same manner, and we end up with ten more names
- added to the list. You will now see why the temporary
- pointer was necessary, but pointers are cheap, so feel free
- to use them at will. A pointer only uses 4 bytes of memory.
-
- We now have generated a linked list of twelve entries.
-
-
- Page 78
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
- We have a pointer pointing at the first entry, and another
- pointer pointing at the last. The only data stored within
- the program itself are three pointers, and one integer, all
- of the dynamically allocated data is on the heap. This is
- one advantage to a linked list, it uses very little internal
- memory, but it is costly in terms of programming. You
- should never use a linked list simply to save memory, but
- only because a certain program lends itself well to it.
- Some sorting routines are extremely fast because of using a
- linked list, and it could be advantageous to use in a
- database.
-
- A graphic picture of the data should aid in your
- understanding of what we have done so far.
-
- StartOfList-->FirstName (first Record)
- Initial
- LastName
- Next---->FirstName (Second Record)
- Initial
- LastName
- Next---->FirstName (Third Record)
- Note; The pointer Initial
- actually points to LastName
- all 4 elements of Next----> etc.
- the record. .
- .
- .
- .
- etc.--->FirstName (Record 11)
- Initial
- LastName
- Next---->FirstName (Record 12)
- Initial
- PlaceInList------->LastName
- Next---->NIL
-
-
- HOW DO WE GET TO THE DATA NOW?
-
- Since the data is in a list, how can we get a copy of
- the fourth entry for example? The only way is to start at
- the beginning of the list and successively examine pointers
- until you reach the desired one. Suppose you are at the
- fourth and then wish to examine the third. You cannot back
- up, because you didn't define the list that way, you can
- only start at the beginning and count to the third. You
- could have defined the record with two pointers, one
- pointing forward, and one pointing backward. This would be
- a doubly-linked list and you could then go directly from
- entry four to entry three.
-
-
- Page 79
-
-
-
-
-
-
-
-
-
- CHAPTER 12 - Pointers and Dynamic Allocation
-
-
-
- Now that the list is defined, we will read the data from
- the list and display it on the video monitor. We begin by
- defining the pointer, "PlaceInList", as the start of the
- list. Now you see why it was important to keep a copy of
- where the list started. In the same manner as filling the
- list, we go from record to record until we find the record
- with NIL as a pointer.
-
- Finally, it is necessary to DEALLOCATE the list, being
- careful to check for the ending NIL before you deallocate
- it. It will be left for you to DEALLOCATE the records if
- you have such a desire.
-
- There are entire books on how to use linked lists, and
- many Modula-2 programmers will seldom, if ever, use them.
- For this reason, additional detail is considered
- unnecessary, but to be a fully informed Modula-2 programmer,
- some insight into linked lists is necessary.
-
- PROGRAMMING EXERCISE
-
- 1. Write a program to store a few names dynamically, then
- display the stored names on the monitor. As your first
- exercise in dynamic allocation, keep it very simple.
-
- 2. For a much more involved project, read in a list of
- simple names and sort them alphabetically by searching
- through the list to find where they should go. Insert
- each new name into the list by changing pointer values.
- For example, to add a new element between number 3 and
- 4, make the pointer in 3 point to the new element, and
- make the pointer in the new element point to number 4.
- It is important to note that adding data to the
- beginning or end of the list must be handled as special
- cases. This is definitely an advanced programming
- exercise but you will be greatly rewarded for your
- effort if you complete it.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 80
-